#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <sys/poll.h>
#include <sys/socket.h>
#include <unistd.h>

#include <iostream>

using namespace std;

#define PORT 8889
#define MAX_EVENTS 10

int main(int argc, char const *argv[]) {
  int s_sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
  if (s_sockfd < 0) {
    perror("Error socket");
    return 1;
  }
  int opt;
  setsockopt(s_sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
  struct sockaddr_in s_addr;
  bzero(&s_addr, sizeof(s_addr));
  s_addr.sin_family = AF_INET;
  s_addr.sin_port = htons(PORT);
  s_addr.sin_addr.s_addr = htonl(INADDR_ANY);
  if (bind(s_sockfd, (struct sockaddr *)&s_addr, sizeof(s_addr)) < 0) {
    perror("Error For bind");
    return 1;
  }
  if (listen(s_sockfd, 5) < 0) {
    perror("Error For listen");
    return 1;
  }

  //   struct pollfd {
  //     int fd;         // 监听的文件描述符
  //     short events;   // 需要监听的事件 （POLLIN,POLLOUT）
  //     short revents;  // 实际发生的事件，由内核填充
  //   }
  // 维护pollfd数组
  struct pollfd events[MAX_EVENTS]{[0] = {.fd = s_sockfd, .events = POLLIN}};
  // 监听事件集合中的有效FD大小
  int num_fds = 1;
  // 等待时间（<0阻塞等待，0不阻塞，>0等待指定时间）
  int timeout = -1;

  int ready;
  while (1) {
    // 返回已就绪事件FD数量
    ready = poll(events, num_fds, timeout);
    if (ready < 0) {
      perror("Error For poll");
      return 1;
    } else if (ready == 0) {
      printf("NO EVENTS TIMEOUT %d SECOND", timeout);
      continue;
    }

    // 遍历FD集合检测有效事件
    for (int i = 0; i < num_fds && ready > 0; ++i) {
      // 无活动
      if (events[i].revents == 0) {
        continue;
      }
      --ready;
      // 新客户端连接
      if (events[i].fd == s_sockfd) {
        struct sockaddr_in c_addr;
        socklen_t c_addrlen;
        int c_sockfd;
        c_addrlen = sizeof(c_addr);
        c_sockfd = accept(s_sockfd, (struct sockaddr *)&c_addr, &c_addrlen);
        if (c_sockfd < 0) {
          perror("Error For accept");
          return 1;
        }
        printf("NEW CLIENT CONNECTED [%s]\n", inet_ntoa(c_addr.sin_addr));
        // 加入事件集合中并检测读事件
        events[num_fds].fd = c_sockfd;
        events[num_fds].events = POLLIN;
        num_fds++;
        continue;
      }
      // 来自客户端的读事件
      int c_eventfd = events[i].fd;
      char buff[1024]{0};
      int n = read(c_eventfd, buff, sizeof(buff));
      if (n <= 0) {
        close(c_eventfd);
        // 移除已读取的FD
        events[i] = events[--num_fds];
        i--;
        printf("CLIENT DISCONNECT\n");
      } else {
        buff[n] = '\0';
        printf("RECV FROM CLIENT -> [%s]\n", buff);
      }
    }
  }

  return 0;
}
